//**************************************************
// Written by Nyi Nyi Than - nyinyithann@gmail.com
// Copyright (c) 2010
// License: The MIT License (MIT)
//**************************************************

using System;
using System.Collections;
using System.Collections.Generic;
using Tanker.Properties;

namespace Tanker
{
    [Serializable]
    public sealed class Sequence<TElement> : IEnumerable<TElement>
    {
        private readonly IEnumerable<TElement> source;

        internal Sequence(IEnumerable<TElement> source)
        {
            Guard.ArgumentNotNull(source, "source");
            this.source = source;
        }

        #region IEnumerable<TElement> Members

        /// <summary>
        /// Returns an enumerator that iterates through the sequence.
        /// </summary>
        /// <returns>Enumerator for the sequence.</returns>
        public IEnumerator<TElement> GetEnumerator()
        {
            return source.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        #endregion

        #region Projecting

        /// <summary>
        /// Projects each element of a sequence into a new form.
        /// </summary>   
        /// <typeparam name="TResult">The type of the value returned by selector.</typeparam>    
        /// <param name="selector">A transform function to apply to each element.</param>              
        /// <returns>The result sequence.</returns>        
        /// <exception cref="ArgumentNullException">Thrown when the given function is null.</exception>
        public Sequence<TResult> Select<TResult>(Func<TElement, TResult> selector)
        {
            Guard.ArgumentNotNull(selector, "selector");
            return new Sequence<TResult>(SelectInternal(selector));
        }

        private IEnumerable<TResult> SelectInternal<TResult>(Func<TElement, TResult> selector)
        {
            foreach (TElement item in source)
            {
                yield return selector(item);
            }
        }

        /// <summary>
        /// Projects each element of a sequence into a new form by incorporating the element's index.
        /// </summary>
        /// <typeparam name="TResult">The type of the value returned by selector.</typeparam>
        /// <param name="selector">A transform function to apply to each source element; the second parameter of the function represents the index of the source element.</param>
        /// <returns>A Sequence whose elements are the result of invoking the transform function on each element of source.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the given function is null.</exception>
        public Sequence<TResult> Select<TResult>(Func<TElement, int, TResult> selector)
        {
            Guard.ArgumentNotNull(selector, "selector");
            return new Sequence<TResult>(SelectInternal(selector));
        }

        private IEnumerable<TResult> SelectInternal<TResult>(Func<TElement, int, TResult> selector)
        {
            int index = 0;
            foreach (TElement item in source)
            {
                yield return selector(item, index++);
            }
        }

        /// <summary>
        /// Merges two sequences by using the specified predicate function.
        /// </summary>
        /// <typeparam name="TSecond">The type of the elements of the second input sequence.</typeparam>
        /// <typeparam name="TResult">The type of the elements of the result sequence.</typeparam>
        /// <param name="second">The second sequence to merge.</param>
        /// <param name="resultSelector">A function that specifies how to merge the elements from the two sequences.</param>
        /// <returns>A sequence that contains merged elements of two input sequences.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the second sequence or resultSelector function is null.</exception>
        public Sequence<TResult> Zip<TSecond, TResult>(IEnumerable<TSecond> second, Func<TElement, TSecond, TResult> resultSelector)
        {
            Guard.ArgumentNotNull(second, "second");
            Guard.ArgumentNotNull(resultSelector, "resultSelector");

            return new Sequence<TResult>(ZipInternal(second, resultSelector));
        }

        private IEnumerable<TResult> ZipInternal<TSecond, TResult>(IEnumerable<TSecond> second, Func<TElement, TSecond, TResult> resultSelector)
        {            
            using(IEnumerator<TElement> firstEnumerator = GetEnumerator())
            {
                using(IEnumerator<TSecond> secondEnumerator = second.GetEnumerator())
                {
                    while(firstEnumerator.MoveNext() && secondEnumerator.MoveNext())
                    {
                        yield return resultSelector(firstEnumerator.Current, secondEnumerator.Current);
                    }
                }
            }
        }

        #endregion

        #region Filtering

        /// <summary>
        /// Returns a new sequence containing only the elements of the sequence for which the given predicate returns true.
        /// </summary>
        /// <param name="predicate">A function to test whether each item in the sequence should be included in the output.</param>
        /// <returns>The result sequence.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the given predicate is null.</exception>
        public Sequence<TElement> Where(Func<TElement, bool> predicate)
        {
            Guard.ArgumentNotNull(predicate, "predicate");
            return new Sequence<TElement>(WhereInternal(predicate));
        }

        private IEnumerable<TElement> WhereInternal(Func<TElement, bool> predicate)
        {
            foreach (TElement item in source)
            {
                if (predicate(item))
                {
                    yield return item;
                }
            }
        }

        /// <summary>
        /// Returns a new sequence containing only the elements of the sequence for which the given predicate returns true.
        /// Each element's index is used in the logic of the predicate function.
        /// </summary>
        /// <param name="predicate">A function to test whether each item in the sequence should be included in the output.</param>
        /// <returns>The result sequence.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the given predicate is null.</exception>
        public Sequence<TElement> Where(Func<TElement, int, bool> predicate)
        {
            Guard.ArgumentNotNull(predicate, "predicate");
            return new Sequence<TElement>(WhereInternal(predicate));
        }

        private IEnumerable<TElement> WhereInternal(Func<TElement, int, bool> predicate)
        {
            int index = 0;
            foreach (TElement item in source)
            {
                if (predicate(item, index++))
                {
                    yield return item;
                }
            }
        }

        /// <summary>
        /// Returns the elements of the sequence up to a specified count.
        /// </summary>
        /// <param name="count">The number of items to take.</param>
        /// <returns>The result sequence.</returns>
        /// <exception cref="ArgumentException">Thrown if count is less than 0.</exception>
        /// <exception cref="InvalidOperationException">Thrown when count exceeds the number of elements in the sequence.</exception>
        public Sequence<TElement> Take(int count)
        {
            Guard.ArgumentNotNegative(count, "count");
            return new Sequence<TElement>(TakeInternal(count));
        }

        private IEnumerable<TElement> TakeInternal(int count)
        {
            using (IEnumerator<TElement> enumerator = GetEnumerator())
            {
                for (int i = 0; i < count; i++)
                {
                    if (!enumerator.MoveNext())
                    {
                        throw new InvalidOperationException(Resources.NotEnoughElements);
                    }

                    yield return enumerator.Current;
                }
            }
        }

        /// <summary>
        /// Returns a sequence that, when iterated, yields elements of the underlying sequence while the given predicate returns true, and then returns no further elements.
        /// </summary>
        /// <param name="predicate">A function that evaluates to false when no more items should be returned.</param>
        /// <returns>The result sequence.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the given predicate is null.</exception>
        public Sequence<TElement> TakeWhile(Func<TElement, bool> predicate)
        {
            Guard.ArgumentNotNull(predicate, "predicate");

            return new Sequence<TElement>(TakeWhileInternal(predicate));
        }

        private IEnumerable<TElement> TakeWhileInternal(Func<TElement, bool> predicate)
        {
            using (IEnumerator<TElement> enumerator = GetEnumerator())
            {
                while (enumerator.MoveNext())
                {
                    TElement temp = enumerator.Current;
                    if (predicate(temp))
                    {
                        yield return temp;
                    }
                    else
                    {
                        yield break;
                    }
                }
            }
        }

        /// <summary>
        /// Bypasses a specified number of elements in a sequence and then returns the remaining elements.
        /// </summary>
        /// <param name="count">The number of elements to skip before returning the remaining elements.</param>
        /// <returns>A Sequence that contains the elements that occur after the specified index in the input sequence.</returns>
        /// <exception cref="ArgumentException">Thrown if count is less than 0.</exception>
        /// <exception cref="InvalidOperationException">Thrown when count exceeds the number of elements in the sequence.</exception>
        public Sequence<TElement> Skip(int count)
        {
            Guard.ArgumentNotNegative(count, "count");
            return new Sequence<TElement>(SkipInternal(count));
        }

        private IEnumerable<TElement> SkipInternal(int count)
        {
            using (IEnumerator<TElement> enumerator = GetEnumerator())
            {
                for (int i = 0; i < count; i++)
                {
                    if (!enumerator.MoveNext())
                    {
                        throw new InvalidOperationException(Resources.NotEnoughElements);
                    }
                }

                while (enumerator.MoveNext())
                {
                    yield return enumerator.Current;
                }
            }
        }

        /// <summary>
        /// Bypasses elements in a sequence as long as a specified condition is true and then returns the remaining elements.
        /// </summary>
        /// <param name="predicate">A function to test each element for a condition.</param>
        /// <returns>A Sequence that contains the elements from the input sequence starting at the first element in the linear series that does not pass the test specified by predicate.</returns>
        /// <exception cref="ArgumentNullException">Thrown when the given predicate is null.</exception>
        public Sequence<TElement> SkipWhile(Func<TElement, bool> predicate)
        {
            Guard.ArgumentNotNull(predicate, "predicate");
            return new Sequence<TElement>(SkipWhileInternal(predicate));
        }

        private IEnumerable<TElement> SkipWhileInternal(Func<TElement, bool> predicate)
        {
            using (IEnumerator<TElement> enumerator = GetEnumerator())
            {
                bool ok = false;
                while (enumerator.MoveNext())
                {
                    TElement temp = enumerator.Current;
                    if (!predicate(temp) || ok)
                    {
                        ok = true;
                        yield return temp;
                    }
                }
            }
        }

        /// <summary>
        /// Returns distinct elements from a sequence by using the default equality comparer to compare values.
        /// </summary>
        /// <returns>An <see cref="Sequence{TElement}"/> that contains distinct elements from the source sequence.</returns>
        public Sequence<TElement> Distinct()
        {
            return Distinct(null);
        }

        /// <summary>
        /// Returns distinct elements from a sequence by using a specified <see cref="System.Collections.Generic.IEqualityComparer{T}"/> to compare values.
        /// </summary>
        /// <param name="comparer">An <see cref="System.Collections.Generic.IEqualityComparer{T}"/> to compare values.</param>
        /// <returns>An <see cref="Sequence{TElement}"/> that contains distinct elements from the source sequence.</returns>
        public Sequence<TElement> Distinct(IEqualityComparer<TElement> comparer)
        {
            return new Sequence<TElement>(DistinctInternal(comparer));
        }

        private IEnumerable<TElement> DistinctInternal(IEqualityComparer<TElement> comparer)
        {
            Dictionary<DistinctKey, object> dictionary = new Dictionary<DistinctKey, object>(new DistinctKeyEqualityComparer(comparer));
            foreach (TElement element in source)
            {
                // Wrap a DistinctKey aroud all keys in case the key type is itself a type using null as a representation
                DistinctKey key = new DistinctKey(element);
                if (!dictionary.ContainsKey(key))
                {
                    dictionary.Add(key, null);
                    yield return element;
                }
            }
        }

        struct DistinctKey
        {
            private readonly TElement value;
            public DistinctKey(TElement value)
            {
                this.value = value;
            }

            public TElement Value
            {
                get
                {
                    return value;
                }
            }
        }

        sealed class DistinctKeyEqualityComparer : IEqualityComparer<DistinctKey>
        {
            private readonly IEqualityComparer<TElement> comparer;

            public DistinctKeyEqualityComparer(IEqualityComparer<TElement> comparer)
            {
                this.comparer = comparer ?? EqualityComparer<TElement>.Default;
            }

            public bool Equals(DistinctKey x, DistinctKey y)
            {
                if (x.Value == null && y.Value == null)
                {
                    return true;
                }
                if (x.Value == null || y.Value == null)
                {
                    return false;
                }

                return comparer.Equals(x.Value, y.Value);
            }

            public int GetHashCode(DistinctKey obj)
            {
                return obj.Value == null ? 0 : comparer.GetHashCode(obj.Value);
            }
        }

        #endregion

        #region Conversion Methods

        /// <summary>
        /// Creates an array from a Sequence.
        /// </summary>
        /// <returns>An array that contains the elements from the sequence.</returns>
        public TElement[] ToArray()
        {
            TElement[] array = null;
            int counter = 0;

            ICollection<TElement> collection = source as ICollection<TElement>;
            if (collection != null)
            {
                array = new TElement[collection.Count];
                collection.CopyTo(array, 0);
                return array;
            }

            using (IEnumerator<TElement> enumerator = GetEnumerator())
            {
                if (!enumerator.MoveNext())
                {
                    array = new TElement[0];
                }
                else
                {
                    array = new TElement[4];
                    array[counter++] = enumerator.Current;
                    while (enumerator.MoveNext())
                    {
                        if (array.Length == counter)
                        {
                            TElement[] temp1 = new TElement[array.Length * 2];
                            Array.Copy(array, 0, temp1, 0, array.Length);
                            array = temp1;
                        }
                        array[counter++] = enumerator.Current;
                    }
                }
            }

            if (counter > 0)
            {
                TElement[] temp2 = new TElement[counter];
                Array.Copy(array, 0, temp2, 0, counter);
                array = temp2;
            }

            return array;
        }

        /// <summary>
        /// Creates a <see cref="System.Collections.Generic.List{TElement}"/> from a sequence.
        /// </summary>
        /// <returns>A <see cref="System.Collections.Generic.List{TElement}"/> that contains elements from the input sequence.</returns>
        public List<TElement> ToList()
        {
            return new List<TElement>(source);
        }

        /// <summary>
        /// Creates a <see cref="Dictionary{TKey, TElement}"/> from a sequence according to a specified key selector function.
        /// </summary>
        /// <typeparam name="TKey">The type of the key returned by keySelector.</typeparam>
        /// <param name="keySelector">A function to extract a key from each element.</param>
        /// <returns>A <see cref="Dictionary{TKey, TElement}"/> that contains keys and values.</returns>
        /// <exception cref="ArgumentNullException">Thrown when keySelector is null or keySelector produces a key that is null
        /// or  keySelector produces duplicate keys for two elements.
        /// </exception>
        public Dictionary<TKey, TElement> ToDictionary<TKey>(Func<TElement, TKey> keySelector)
        {
            Func<TElement, TElement> valueSelector = delegate(TElement element) { return element; };
            return ToDictionary(keySelector, valueSelector, null);
        }

        /// <summary>
        /// Creates a <see cref="Dictionary{TKey, TElement}"/> from a sequence according to a specified key selector function and key comparer.
        /// </summary>
        /// <typeparam name="TKey">The type of the key returned by keySelector.</typeparam>
        /// <param name="keySelector">A function to extract a key from each element.</param>
        /// <param name="comparer">An <see cref="System.Collections.Generic.IEqualityComparer{TElement}"/> to compare keys.</param>
        /// <returns>A <see cref="Dictionary{TKey, TElement}"/> that contains keys and values.</returns>
        /// <exception cref="ArgumentNullException">Thrown when keySelector is null or keySelector produces a key that is null
        /// or  keySelector produces duplicate keys for two elements.
        /// </exception>
        public Dictionary<TKey, TElement> ToDictionary<TKey>(Func<TElement, TKey> keySelector, IEqualityComparer<TKey> comparer)
        {
            Func<TElement, TElement> valueSelector = delegate(TElement element) { return element; };
            return ToDictionary(keySelector, valueSelector, comparer);
        }

        /// <summary>
        /// Creates a <see cref="Dictionary{TKey, TValue}"/> from a sequence according to specified key selector and element selector functions.
        /// </summary>
        /// <typeparam name="TKey">The type of the key returned by keySelector.</typeparam>
        /// <typeparam name="TValue">The type of the value returned by elementSelector.</typeparam>
        /// <param name="keySelector">A function to extract a key from each element.</param>
        /// <param name="valueSelector">A transform function to produce a result element value from each element.</param>
        /// <returns>A <see cref="Dictionary{TKey, TValue}"/> that contains keys and values.</returns>
        /// <exception cref="ArgumentNullException">Thrown when keySelector or valueSelector is null or keySelector produces a key that is null
        /// or  keySelector produces duplicate keys for two elements.
        /// </exception>
        public Dictionary<TKey, TValue> ToDictionary<TKey, TValue>(Func<TElement, TKey> keySelector, Func<TElement, TValue> valueSelector)
        {
            return ToDictionary(keySelector, valueSelector, null);
        }

        /// <summary>
        /// Creates a <see cref="Dictionary{TKey, TValue}"/> from a sequence according to specified a key selector, a comparer, and an element selector function.
        /// </summary>
        /// <typeparam name="TKey">The type of the key returned by keySelector.</typeparam>
        /// <typeparam name="TValue">The type of the value returned by elementSelector.</typeparam>
        /// <param name="keySelector">A function to extract a key from each element.</param>
        /// <param name="valueSelector">A transform function to produce a result element value from each element.</param>
        /// <param name="comparer">An <see cref="System.Collections.Generic.IEqualityComparer{TElement}"/> to compare keys.</param>
        /// <returns>A <see cref="Dictionary{TKey, TValue}"/> that contains keys and values.</returns>
        /// <exception cref="ArgumentNullException">Thrown when keySelector or valueSelector is null or keySelector produces a key that is null
        /// or  keySelector produces duplicate keys for two elements.
        /// </exception>
        public Dictionary<TKey, TValue> ToDictionary<TKey, TValue>(Func<TElement, TKey> keySelector, Func<TElement, TValue> valueSelector, IEqualityComparer<TKey> comparer)
        {
            Guard.ArgumentNotNull(keySelector, "keySelector");
            Guard.ArgumentNotNull(valueSelector, "valueSelector");

            Dictionary<TKey, TValue> dictionary = new Dictionary<TKey, TValue>(comparer);
            foreach (TElement element in source)
            {
                dictionary.Add(keySelector(element), valueSelector(element));
            }

            return dictionary;
        }

        /// <summary>
        /// Creates <see cref="ArrayList"/> which contains all the elements of the sequence.
        /// </summary>
        /// <returns><see cref="ArrayList"/> containing all the elements of the sequence.</returns>
        public ArrayList ToArrayList()
        {
            ICollection collection = source as ICollection;
            if (collection != null)
            {
                return new ArrayList(collection);
            }

            ArrayList arrayList = new ArrayList(Count());
            foreach (TElement element in source)
            {
                arrayList.Add(element);
            }

            return arrayList;
        }

        #endregion

        #region Element Operators

        /// <summary>
        /// Returns the first element of a sequence.
        /// </summary>
        /// <returns>The first element in the specified sequence.</returns>
        /// <exception cref="InvalidOperationException">Thrown if the source sequence is empty.</exception>
        public TElement First()
        {
            IList<TElement> list = source as IList<TElement>;
            if (list != null)
            {
                if (list.Count > 0)
                {
                    return list[0];
                }
            }
            else
            {
                using (IEnumerator<TElement> enumerator = GetEnumerator())
                {
                    if (enumerator.MoveNext())
                    {
                        return enumerator.Current;
                    }
                }
            }

            throw new InvalidOperationException(Resources.NotEnoughElements);
        }

        /// <summary>
        /// Returns the first element in a sequence that satisfies a specified condition.
        /// </summary>
        /// <param name="predicate"> A function to test each element for a condition.</param>
        /// <returns>The first element in the sequence that passes the test in the specified predicate function.</returns>
        /// <exception cref="ArgumentException">Thrown if the predicate function is null.</exception>
        /// <exception cref="InvalidOperationException">Thrown when no element satisfies the condition in predicate or the source sequence is empty.</exception>
        public TElement First(Func<TElement, bool> predicate)
        {
            Guard.ArgumentNotNull(predicate, "predicate");

            foreach (TElement element in source)
            {
                if (predicate(element))
                {
                    return element;
                }
            }

            throw new InvalidOperationException(Resources.NoMatch);
        }

        /// <summary>
        /// Returns the first element of a sequence, or a default value if the sequence contains no elements.
        /// </summary>
        /// <returns>default(TSource) if source is empty; otherwise, the first element in source.</returns>
        public TElement FirstOrDefault()
        {
            return FirstOrDefaultInternal();
        }

        /// <summary>
        /// Returns the first element of the sequence that satisfies a condition or a default value if no such element is found.
        /// </summary>
        /// <param name="predicate">A function to test each element for a condition.</param>
        /// <returns>default(TSource) if source is empty or if no element passes the test specified by predicate; otherwise, the first element in source that passes the test specified by predicate.</returns>
        /// <exception cref="ArgumentNullException">Thrown if the predicate is null.</exception>
        public TElement FirstOrDefault(Func<TElement, bool> predicate)
        {
            Guard.ArgumentNotNull(predicate, "predicate");

            foreach (TElement item in source)
            {
                if (predicate(item))
                {
                    return item;
                }
            }

            return default(TElement);
        }

        private TElement FirstOrDefaultInternal()
        {
            IList<TElement> list = source as IList<TElement>;
            if (list != null)
            {
                if (list.Count > 0)
                {
                    return list[0];
                }
            }
            else
            {
                using (IEnumerator<TElement> enumerator = GetEnumerator())
                {
                    if (enumerator.MoveNext())
                    {
                        return enumerator.Current;
                    }
                }
            }

            return default(TElement);
        }

        /// <summary>
        /// Returns the last element of a sequence.
        /// </summary>
        /// <returns>The value at the last position in the source sequence.</returns>
        /// <exception cref="InvalidOperationException">Thrown when the source sequence is empty.</exception>
        public TElement Last()
        {
            IList<TElement> list = source as IList<TElement>;
            if (list != null)
            {
                int count = list.Count;
                if (count > 0)
                {
                    return list[count - 1];
                }
            }
            else
            {
                using (IEnumerator<TElement> enumerator = GetEnumerator())
                {
                    if (enumerator.MoveNext())
                    {
                        TElement current;
                        do
                        {
                            current = enumerator.Current;
                        } while (enumerator.MoveNext());

                        return current;
                    }
                }
            }

            throw new InvalidOperationException(Resources.NotEnoughElements);
        }

        /// <summary>
        /// Returns the last element of a sequence that satisfies a specified condition.
        /// </summary>
        /// <param name="predicate"> A function to test each element for a condition.</param>
        /// <returns>The last element in the sequence that passes the test in the specified predicate function.</returns>
        /// <exception cref="ArgumentNullException">Thrown if the predicate is null.</exception>
        /// <exception cref="InvalidOperationException">Thrown when no element satisfies the condition in predicate or the source sequence is empty.</exception>
        public TElement Last(Func<TElement, bool> predicate)
        {
            Guard.ArgumentNotNull(predicate, "predicate");

            TElement lastElement = default(TElement);
            bool ok = false;
            foreach (TElement element in source)
            {
                if (predicate(element))
                {
                    lastElement = element;
                    ok = true;
                }
            }

            if (!ok)
            {
                throw new InvalidOperationException(Resources.NoMatch);
            }

            return lastElement;
        }

        /// <summary>
        /// Returns the last element of a sequence, or a default value if the sequence contains no elements.
        /// </summary>
        /// <returns> default(TSource) if the source sequence is empty; otherwise, the last element in the sequence.</returns>
        public TElement LastOrDefault()
        {
            IList<TElement> list = source as IList<TElement>;
            if (list != null)
            {
                int count = list.Count;
                if (count > 0)
                {
                    return list[count - 1];
                }
            }
            else
            {
                using (IEnumerator<TElement> enumerator = GetEnumerator())
                {
                    if (enumerator.MoveNext())
                    {
                        TElement current;
                        do
                        {
                            current = enumerator.Current;
                        } while (enumerator.MoveNext());

                        return current;
                    }
                }
            }

            return default(TElement);
        }

        /// <summary>
        /// Returns the last element of a sequence that satisfies a condition or a default value if no such element is found.
        /// </summary>
        /// <param name="predicate"> A function to test each element for a condition.</param>
        /// <returns> default(TSource) if the sequence is empty or if no elements pass the test in the predicate function; otherwise, the last element that passes the test in the predicate function.</returns>
        /// <exception cref="ArgumentNullException">Thrown if the predicate is null.</exception>
        public TElement LastOrDefault(Func<TElement, bool> predicate)
        {
            Guard.ArgumentNotNull(predicate, "predicate");

            TElement lastElement = default(TElement);

            foreach (TElement element in source)
            {
                if (predicate(element))
                {
                    lastElement = element;
                }
            }

            return lastElement;
        }

        /// <summary>
        /// Returns the only element of a sequence, and throws an exception if there is not exactly one element in the sequence.
        /// </summary>
        /// <returns>The single element of the input sequence.</returns>
        /// <exception cref="InvalidOperationException">Thrown when the input sequence contains more than one element or the input sequence is empty.</exception>
        public TElement Single()
        {
            IList<TElement> list = source as IList<TElement>;
            if (list != null)
            {
                int count = list.Count;
                switch (count)
                {
                    case 0:
                        throw new InvalidOperationException(Resources.NotEnoughElements);
                    case 1:
                        return list[0];
                }
            }
            else
            {
                using (IEnumerator<TElement> enumerator = GetEnumerator())
                {
                    if (!enumerator.MoveNext())
                    {
                        throw new InvalidOperationException(Resources.NotEnoughElements);
                    }

                    TElement element = enumerator.Current;

                    if (!enumerator.MoveNext())
                    {
                        return element;
                    }
                }
            }

            throw new InvalidOperationException(Resources.MoreThanOneElement);
        }


        /// <summary>
        /// Returns the only element of a sequence that satisfies a specified condition, and throws an exception if more than one such element exists.
        /// </summary>
        /// <param name="predicate">A function to test an element for a condition.</param>
        /// <returns>The single element of the input sequence that satisfies a condition.</returns>
        /// <exception cref="InvalidOperationException">Thrown when no element satisfies the condition in predicate or more than one element satisfies the condition in predicate or the source sequence is empty.</exception>
        public TElement Single(Func<TElement, bool> predicate)
        {
            Guard.ArgumentNotNull(predicate, "predicate");

            TElement expectedElement = default(TElement);
            long counter = 0L;
            foreach (TElement element in source)
            {
                if (predicate(element))
                {
                    expectedElement = element;
                    counter++;
                }
            }

            switch (counter)
            {
                case 0:
                    throw new InvalidOperationException(Resources.NoMatch);
                case 1:
                    return expectedElement;
                default:
                    throw new InvalidOperationException(Resources.MoreThanOneMatch);
            }
        }

        /// <summary>
        /// Returns the only element of a sequence, or a default value if the sequence is empty; this method throws an exception if there is more than one element in the sequence.
        /// </summary>
        /// <returns>The single element of the input sequence, or default(TSource) if the sequence contains no elements.</returns>
        /// <exception cref="InvalidOperationException">Thrown when the input sequence contains more than one element.</exception>
        public TElement SingleOrDefault()
        {
            IList<TElement> list = source as IList<TElement>;
            if (list != null)
            {
                int count = list.Count;
                switch (count)
                {
                    case 0:
                        return default(TElement);
                    case 1:
                        return list[0];
                }
            }
            else
            {
                using (IEnumerator<TElement> enumerator = GetEnumerator())
                {
                    if (!enumerator.MoveNext())
                    {
                        return default(TElement);
                    }

                    TElement element = enumerator.Current;

                    if (!enumerator.MoveNext())
                    {
                        return element;
                    }
                }
            }

            throw new InvalidOperationException(Resources.MoreThanOneElement);
        }

        /// <summary>
        /// Returns the only element of a sequence that satisfies a specified condition or a default value if no such element exists; this method throws an exception if more than one element satisfies the condition.
        /// </summary>
        /// <param name="predicate">A function to test an element for a condition.</param>
        /// <returns>The single element of the input sequence that satisfies the condition, or default(TSource) if no such element is found.</returns>
        /// <exception cref="InvalidOperationException"> Thrown when more than one element satisfies the condition in predicate.</exception>
        public TElement SingleOrDefault(Func<TElement, bool> predicate)
        {
            Guard.ArgumentNotNull(predicate, "predicate");

            TElement expectedElement = default(TElement);
            long counter = 0L;
            foreach (TElement element in source)
            {
                if (predicate(element))
                {
                    expectedElement = element;
                    counter++;
                }
            }

            switch (counter)
            {
                case 0:
                case 1:
                    return expectedElement;
                default:
                    throw new InvalidOperationException(Resources.MoreThanOneMatch);
            }
        }

        /// <summary>
        /// Returns the element at a specified index in a sequence.
        /// </summary>
        /// <param name="index">The zero-based index of the element to retrieve.</param>
        /// <returns>The element at the specified position in the source sequence.</returns>
        /// <exception cref="ArgumentException">Thrown when index is less than 0 or the sequence has an insufficient number of elements.</exception>
        public TElement ElementAt(int index)
        {
            using (IEnumerator<TElement> enumerator = GetEnumerator())
            {
                return ElementAtInternal(enumerator, index);
            }
        }

        private TElement ElementAtInternal(IEnumerator<TElement> enumerator, int index)
        {
            Guard.ArgumentNotNegative(index, "index");

            if (!enumerator.MoveNext())
            {
                throw new ArgumentException(Resources.NotEnoughElements);
            }

            return index == 0
                       ? enumerator.Current
                       : ElementAtInternal(enumerator, index - 1);
        }

        /// <summary>
        /// Returns the element at a specified index in a sequence or a default value if the index is less than 0 or the sequence has an insufficient number of elements.
        /// </summary>
        /// <param name="index">the sequence has an insufficient number of elements</param>
        /// <returns>default(TSource) if the index is outside the bounds of the source sequence; 
        /// otherwise, the element at the specified position in the source sequence.
        ///</returns>
        public TElement ElementAtOrDefault(int index)
        {
            using (IEnumerator<TElement> enumerator = GetEnumerator())
            {
                return ElementAtOrDefaultInternal(enumerator, index);
            }
        }

        private TElement ElementAtOrDefaultInternal(IEnumerator<TElement> enumerator, int index)
        {
            if (index < 0)
            {
                return default(TElement);
            }

            if (!enumerator.MoveNext())
            {
                return default(TElement);
            }

            return index == 0
                       ? enumerator.Current
                       : ElementAtOrDefaultInternal(enumerator, index - 1);
        }

        /// <summary>
        /// Tests whether a sequence has any elements.
        /// </summary>
        /// <returns> true if the input sequence is empty. Otherwise, returns false.</returns>
        public bool IsEmpty()
        {
            ICollection<TElement> collection1 = source as ICollection<TElement>;
            if (collection1 != null)
            {
                return collection1.Count == 0;
            }

            using (IEnumerator<TElement> enumerator = GetEnumerator())
            {
                return !enumerator.MoveNext();
            }
        }

        /// <summary>
        /// Returns the elements of the specified sequence or the type parameter's default value in a singleton collection if the sequence is empty.
        /// </summary>
        /// <returns>A sequence that contains default(TElement) if this sequence is empty; otherwise, this sequence.</returns>
        public Sequence<TElement> DefaultIfEmpty()
        {
            return DefaultIfEmpty(default(TElement));
        }

        /// <summary>
        /// Returns the elements of the specified sequence or the specified value in a singleton collection if the sequence is empty.
        /// </summary>
        /// <param name="defaultValue"> The value to return if the sequence is empty.</param>
        /// <returns>A sequence that contains defaultValue if this sequence is empty; otherwise, this sequence.</returns>
        public Sequence<TElement> DefaultIfEmpty(TElement defaultValue)
        {
            return IsEmpty()
                       ? Sequence.Singleton(defaultValue)
                       : this;
        }

        #endregion

        #region Aggregation Methods

        /// <summary>
        /// Returns the number of elements in a sequence.
        /// </summary>
        /// <returns>The number of elements in the sequence.</returns>
        /// <exception cref="System.OverflowException">The number of elements in source is larger than System.Int32.MaxValue.</exception>
        public int Count()
        {
            ICollection<TElement> col1 = source as ICollection<TElement>;
            if (col1 != null)
            {
                return col1.Count;
            }

            int num = 0;

            using (IEnumerator<TElement> enumerator = GetEnumerator())
            {
                while (enumerator.MoveNext())
                {
                    num++;
                }
            }
            return num;
        }

        /// <summary>
        /// Returns a number that represents how many elements in the specified sequence satisfy a condition.
        /// </summary>
        /// <param name="predicate">A function to test each element for a condition.</param>
        /// <returns>A number that represents how many elements in the sequence satisfy the condition in the predicate function.</returns>
        /// <exception cref="ArgumentException">Thrown when the predicate is null.</exception>
        /// <exception cref="System.OverflowException">The number of elements in source is larger than System.Int32.MaxValue.</exception>
        public int Count(Func<TElement, bool> predicate)
        {
            Guard.ArgumentNotNull(predicate, "predicate");

            int num = 0;

            using (IEnumerator<TElement> enumerator = GetEnumerator())
            {
                while (enumerator.MoveNext())
                {
                    if (predicate(enumerator.Current))
                    {
                        num++;
                    }
                }
            }
            return num;
        }

        /// <summary>
        /// Returns an System.Int64 that represents the total number of elements in a sequence.
        /// </summary>
        /// <returns>The number of elements in the source sequence.</returns>
        /// <exception cref="System.OverflowException">The number of elements in source is larger than System.Int64.MaxValue.</exception>
        public long LongCount()
        {
            ICollection<TElement> col1 = source as ICollection<TElement>;
            if (col1 != null)
            {
                return col1.Count;
            }

            long num = 0L;

            using (IEnumerator<TElement> enumerator = GetEnumerator())
            {
                while (enumerator.MoveNext())
                {
                    num++;
                }
            }
            return num;
        }

        /// <summary>
        /// Returns an System.Int64 that represents how many elements in a sequence satisfy a condition.
        /// </summary>
        /// <param name="predicate">A function to test each element for a condition.</param>
        /// <returns>A number that represents how many elements in the sequence satisfy the condition in the predicate function.</returns>
        /// <exception cref="ArgumentException">Thrown when the predicate is null.</exception>
        /// <exception cref="System.OverflowException">The number of elements in source is larger than System.Int64.MaxValue.</exception>
        public long LongCount(Func<TElement, bool> predicate)
        {
            Guard.ArgumentNotNull(predicate, "predicate");

            long num = 0L;

            using (IEnumerator<TElement> enumerator = GetEnumerator())
            {
                while (enumerator.MoveNext())
                {
                    if (predicate(enumerator.Current))
                    {
                        num++;
                    }
                }
            }
            return num;
        }

        /// <summary>
        /// Applies an accumulator function over a sequence.
        /// </summary>
        /// <param name="accumulator">An accumulator function to be invoked on each element.</param>
        /// <returns>The final accumulator value.</returns>
        /// <exception cref="ArgumentNullException">Thrown if accumulator is null.</exception>
        /// <exception cref="InvalidOperationException">Thrown if the sequence contains no elements.</exception>
        public TElement Aggregate(Func<TElement, TElement, TElement> accumulator)
        {
            Guard.ArgumentNotNull(accumulator, "accumulator");

            using (IEnumerator<TElement> enumerator = GetEnumerator())
            {
                if (!enumerator.MoveNext())
                {
                    throw new InvalidOperationException(Resources.NotEnoughElements);
                }

                TElement current = enumerator.Current;
                while (enumerator.MoveNext())
                {
                    current = accumulator(current, enumerator.Current);
                }

                return current;
            }
        }

        /// <summary>
        /// Applies an accumulator function over a sequence. The specified function is used to select the result value.
        /// </summary>
        /// <typeparam name="TResult">The type of the resulting value.</typeparam>
        /// <param name="accumulator">An accumulator function to be invoked on each element.</param>
        /// <param name="resultSelector">A function to transform the final accumulator value into the result value.</param>
        /// <returns>The transformed final accumulator value.</returns>
        /// <exception cref="ArgumentNullException">Thrown if accumulator or resultSelector is null.</exception>
        /// <exception cref="InvalidOperationException">Thrown if the sequence contains no elements.</exception>
        public TResult Aggregate<TResult>(Func<TElement, TElement, TElement> accumulator, Func<TElement, TResult> resultSelector)
        {
            Guard.ArgumentNotNull(resultSelector, "resultSelector");

            TElement result = Aggregate(accumulator);
            return resultSelector(result);
        }

        /// <summary>
        /// Applies an accumulator function over a sequence. The specified seed value is used as the initial accumulator value.
        /// </summary>
        /// <typeparam name="TAccumulate">The type of the accumulator value.</typeparam>
        /// <param name="seed">The initial accumulator value.</param>
        /// <param name="accumulator">An accumulator function to be invoked on each element.</param>
        /// <returns>The final accumulator value.</returns>
        /// <exception cref="ArgumentNullException">Thrown if accumulator is null.</exception>
        public TAccumulate Aggregate<TAccumulate>(TAccumulate seed, Func<TAccumulate, TElement, TAccumulate> accumulator)
        {
            Guard.ArgumentNotNull(accumulator, "accumulator");

            TAccumulate accumulate = seed;
            using (IEnumerator<TElement> enumerator = GetEnumerator())
            {
                while (enumerator.MoveNext())
                {
                    accumulate = accumulator(accumulate, enumerator.Current);
                }

                return accumulate;
            }

        }

        /// <summary>
        /// Applies an accumulator function over a sequence. The specified seed value is used as the initial accumulator value, and the specified function is used to select the result value.
        /// </summary>
        /// <typeparam name="TAccumulate">The type of the accumulator value.</typeparam>
        /// <typeparam name="TResult">The type of the resulting value.</typeparam>
        /// <param name="seed">The initial accumulator value.</param>
        /// <param name="accumulator">An accumulator function to be invoked on each element.</param>
        /// <param name="resultSelector">A function to transform the final accumulator value into the result value.</param>
        /// <returns>The transformed final accumulator value.</returns>
        /// <exception cref="ArgumentNullException">Thrown if accumulator or resultSelector is null.</exception>
        public TResult Aggregate<TAccumulate, TResult>(TAccumulate seed, Func<TAccumulate, TElement, TAccumulate> accumulator, Func<TAccumulate, TResult> resultSelector)
        {
            Guard.ArgumentNotNull(resultSelector, "resultSelector");

            TAccumulate result = Aggregate(seed, accumulator);
            return resultSelector(result);
        }



        #endregion

        #region Iteration Methods

        /// <summary>
        /// Applies the given function to each element of the collection.
        /// </summary>
        /// <param name="action">A function to apply to each element of the sequence.</param>
        /// <exception cref="System.ArgumentNullException">Thrown when the action is null.</exception>
        public void ForEach(Action<TElement> action)
        {
            Guard.ArgumentNotNull(action, "action");
            foreach (TElement item in this)
            {
                action(item);
            }
        }

        #endregion

        #region Quantifier Methods

        /// <summary>
        /// Determines whether two sequences are equal by comparing the elements by using the default equality comparer for their type.
        /// </summary>
        /// <param name="second">A sequence to compare to the first sequence.</param>
        /// <returns>true if the two source sequences are of equal length and their corresponding elements are equal according to the default equality comparer for their type; otherwise, false.</returns>
        /// <exception cref="ArgumentNullException">Thrown if second is null.</exception>
        public bool SequentialEqual(Sequence<TElement> second)
        {
            return SequentialEqual(second, null);
        }

        /// <summary>
        /// Determines whether two sequences are equal by comparing their elements by using a specified System.Collections.Generic.IEqualityComparer<T>.
        /// </summary>
        /// <param name="second">A sequence to compare to the first sequence.</param>
        /// <param name="comparer">An <see cref="System.Collections.Generic.IEqualityComparer{TElement}"/> to use to compare elements.</param>
        /// <returns>true if the two source sequences are of equal length and their corresponding elements compare equal according to comparer; otherwise, false.</returns>
        /// <exception cref="ArgumentNullException">Thrown if second is null.</exception>
        public bool SequentialEqual(Sequence<TElement> second, IEqualityComparer<TElement> comparer)
        {
            Guard.ArgumentNotNull(second, "second");

            comparer = comparer ?? EqualityComparer<TElement>.Default;

            using (IEnumerator<TElement> enumerator = GetEnumerator())
            {
                using (IEnumerator<TElement> enumerator2 = second.GetEnumerator())
                {
                    while (enumerator.MoveNext())
                    {
                        if (!enumerator2.MoveNext() || !comparer.Equals(enumerator.Current, enumerator2.Current))
                        {
                            return false;
                        }
                    }

                    if (enumerator2.MoveNext())
                    {
                        return false;
                    }
                }
            }

            return true;
        }

        /// <summary>
        /// Determines whether a sequence contains any elements.
        /// </summary>
        /// <returns>true if the source sequence contains any elements; otherwise, false.</returns>
        public bool Any()
        {
            using (IEnumerator<TElement> enumerator = GetEnumerator())
            {
                return enumerator.MoveNext();
            }
        }

        /// <summary>
        /// Determines whether any element of a sequence satisfies a condition.
        /// </summary>
        /// <param name="predicate">A function to test each element for a condition.</param>
        /// <returns>true if any elements in the source sequence pass the test in the specified predicate; otherwise, false.</returns>
        /// <exception cref="ArgumentException">Thrown if the predicate is null.</exception>
        public bool Any(Func<TElement, bool> predicate)
        {
            Guard.ArgumentNotNull(predicate, "predicate");

            using (IEnumerator<TElement> enumerator = GetEnumerator())
            {
                while (enumerator.MoveNext())
                {
                    if (predicate(enumerator.Current))
                    {
                        return true;
                    }
                }
            }

            return false;
        }

        /// <summary>
        /// Determines whether all elements of a sequence satisfy a condition.
        /// </summary>
        /// <param name="predicate"> A function to test each element for a condition.</param>
        /// <returns>true if every element of the source sequence passes the test in the specified predicate, or if the sequence is empty; otherwise, false.</returns>
        /// <exception cref="ArgumentException">Thrown if the predicate is null.</exception>
        public bool All(Func<TElement, bool> predicate)
        {
            Guard.ArgumentNotNull(predicate, "predicate");

            using (IEnumerator<TElement> enumerator = GetEnumerator())
            {
                while (enumerator.MoveNext())
                {
                    if (!predicate(enumerator.Current))
                    {
                        return false;
                    }
                }
            }

            return true;
        }

        /// <summary>
        /// Determines whether a sequence contains a specified element by using the default equality comparer.
        /// </summary>
        /// <param name="element">The element to locate in the sequence.</param>
        /// <returns>true if the source sequence contains an element that has the specified value; otherwise, false.</returns>
        public bool Contains(TElement element)
        {
            ICollection<TElement> collection = source as ICollection<TElement>;
            if (collection != null)
            {
                return collection.Contains(element);
            }

            return Contains(element, null);
        }

        /// <summary>
        /// Determines whether a sequence contains a specified element by using a specified <see cref="System.Collections.Generic.IEqualityComparer{TElement}"/>.
        /// </summary>
        /// <param name="element">The element to locate in the sequence.</param>
        /// <param name="comparer">An equality comparer to compare values.</param>
        /// <returns>true if the source sequence contains an element that has the specified value; otherwise, false.</returns>
        public bool Contains(TElement element, IEqualityComparer<TElement> comparer)
        {
            if (comparer == null)
            {
                comparer = EqualityComparer<TElement>.Default;
            }

            using (IEnumerator<TElement> enumerator = GetEnumerator())
            {
                while (enumerator.MoveNext())
                {
                    if (comparer.Equals(element, enumerator.Current))
                    {
                        return true;
                    }
                }
            }

            return false;
        }

        #endregion

        #region Ordering

        /// <summary>
        /// Inverts the order of the elements in this sequence.
        /// </summary>
        /// <returns>A sequence whose elements correspond to those of the input sequence in reverse order.</returns>
        public Sequence<TElement> Reverse()
        {
            if (IsEmpty())
            {
                return this;
            }

            TElement[] array = ToArray();
            Array.Reverse(array, 0, array.Length);

            return Sequence.Create(array);
        }

        #endregion

        #region Set Operators

        /// <summary>
        /// Concatenates two sequences.
        /// </summary>
        /// <param name="second">The sequence to concatenate to the first sequence.</param>
        /// <returns>A sequence that contains the concatenated elements of the two input sequences.</returns>
        /// <exception cref="ArgumentNullException">Thrown if second is null.</exception>
        public Sequence<TElement> Concat(IEnumerable<TElement> second)
        {
            return new Sequence<TElement>(ConcatInternal(second));
        }

        private IEnumerable<TElement> ConcatInternal(IEnumerable<TElement> second)
        {
            Guard.ArgumentNotNull(second, "second");
            foreach (TElement element in source)
            {
                yield return element;
            }

            foreach (TElement element in second)
            {
                yield return element;
            }
        }

        /// <summary>
        /// Produces the set union of two sequences by using the default equality comparer.
        /// </summary>
        /// <param name="second">An <see cref="System.Collections.Generic.IEnumerable{TElement}"/> whose distinct elements form the second set for the union.</param>
        /// <returns>A <see cref="Sequence{TElement}"/> that contains the elements from both input sequences, excluding duplicates.</returns>
        /// <exception cref="ArgumentNullException">Thrown if second is null.</exception>
        public Sequence<TElement> Union(IEnumerable<TElement> second)
        {
            return Union(second, null);
        }

        /// <summary>
        /// Produces the set union of two sequences by using a specified <see cref="System.Collections.Generic.IEqualityComparer{TElement}"/>.
        /// </summary>
        /// <param name="second">An <see cref="System.Collections.Generic.IEnumerable{TElement}"/> whose distinct elements form the second set for the union.</param>
        /// <param name="comparer">The <see cref="System.Collections.Generic.IEqualityComparer{TElement}"/> to compare values.</param>
        /// <returns>A <see cref="Sequence{TElement}"/> that contains the elements from both input sequences, excluding duplicates.</returns>
        /// <exception cref="ArgumentNullException">Thrown if second is null.</exception>
        public Sequence<TElement> Union(IEnumerable<TElement> second, IEqualityComparer<TElement> comparer)
        {
            Guard.ArgumentNotNull(second, "second");

            return Concat(second).Distinct(comparer);
        }

        /// <summary>
        /// Produces the set intersection of two sequences by using the default equality comparer to compare values.
        /// </summary>
        /// <param name="second">An <see cref="System.Collections.Generic.IEnumerable{TElement}"/> whose distinct elements that also appear in the first sequence will be returned.</param>
        /// <returns>A sequence that contains the elements that form the set intersection of two sequences.</returns>
        /// <exception cref="ArgumentNullException">Thrown if second is null.</exception>
        public Sequence<TElement> Intersect(IEnumerable<TElement> second)
        {
            return Intersect(second, null);
        }

        /// <summary>
        /// Produces the set intersection of two sequences by using the specified <see cref="System.Collections.Generic.IEqualityComparer{TElement}"/> to compare values.
        /// </summary>
        /// <param name="second">An <see cref="System.Collections.Generic.IEnumerable{TElement}"/> whose distinct elements form the second set for the union.</param>
        /// <param name="comparer">The <see cref="System.Collections.Generic.IEqualityComparer{TElement}"/> to compare values.</param>
        /// <returns>A sequence that contains the elements that form the set intersection of two sequences.</returns>
        /// <exception cref="ArgumentNullException">Thrown if second is null.</exception>
        public Sequence<TElement> Intersect(IEnumerable<TElement> second, IEqualityComparer<TElement> comparer)
        {
            Guard.ArgumentNotNull(second, "second");
            return new Sequence<TElement>(IntersectInternal(second, comparer));
        }

        private IEnumerable<TElement> IntersectInternal(IEnumerable<TElement> second, IEqualityComparer<TElement> comparer)
        {
            comparer = comparer ?? EqualityComparer<TElement>.Default;
            foreach (TElement element in second)
            {
                if (Contains(element, comparer))
                {
                    yield return element;
                }
            }
        }

        /// <summary>
        /// Produces the set difference of two sequences by using the default equality comparer to compare values.
        /// </summary>
        /// <param name="second">An <see cref="System.Collections.Generic.IEnumerable{TElement}"/>  whose elements that also occur in the first sequence will cause those elements to be removed from the returned sequence.</param>
        /// <returns>A sequence that contains the set difference of the elements of two sequences.</returns>
        /// <exception cref="ArgumentNullException">Thrown if second is null.</exception>
        public Sequence<TElement> Except(IEnumerable<TElement> second)
        {
            return Except(second, null);
        }

        /// <summary>
        /// Produces the set difference of two sequences by using the specified <see cref="System.Collections.Generic.IEqualityComparer{TElement}"/> to compare values.
        /// </summary>
        /// <param name="second">An <see cref="System.Collections.Generic.IEnumerable{TElement}"/>  whose elements that also occur in the first sequence will cause those elements to be removed from the returned sequence.</param>
        /// <param name="comparer">The <see cref="System.Collections.Generic.IEqualityComparer{TElement}"/> to compare values.</param>
        /// <returns>A sequence that contains the set difference of the elements of two sequences.</returns>
        /// <exception cref="ArgumentNullException">Thrown if second is null.</exception>
        public Sequence<TElement> Except(IEnumerable<TElement> second, IEqualityComparer<TElement> comparer)
        {
            Guard.ArgumentNotNull(second, "second");
            return new Sequence<TElement>(ExceptInternal(second, comparer));
        }

        private IEnumerable<TElement> ExceptInternal(IEnumerable<TElement> second, IEqualityComparer<TElement> comparer)
        {
            Sequence<TElement> secondSeq = second is Sequence<TElement>
                                            ? second as Sequence<TElement>
                                            : new Sequence<TElement>(second);

            comparer = comparer ?? EqualityComparer<TElement>.Default;
            foreach (TElement element in this)
            {
                if (!secondSeq.Contains(element, comparer))
                {
                    yield return element;
                }
            }
        }

        #endregion

    }
}